package com.hero.take.core.exception;

import cn.dev33.satoken.exception.NotLoginException;
import com.hero.take.entity.result.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.security.auth.message.AuthException;
import java.net.BindException;
import java.util.List;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(AuthException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> authExceptionHandler(AuthException ex) {
        return buildResult(ex.getMessage(), 403, ex);
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> businessExceptionHandler(BusinessException ex) {
        return buildResult(ex.getMessage(), 520, ex);
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> httpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException ex) {
        return buildResult(HttpStatus.UNSUPPORTED_MEDIA_TYPE.getReasonPhrase(), HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), ex);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) {
        return buildResult("缺少必要参数:" + ex.getParameterName(), HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ExceptionHandler(BindException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> bindExceptionHandler(BindException ex) {
        return buildResult("绑定参数异常", HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        return buildResult("参数读取异常", HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ExceptionHandler(org.springframework.validation.BindException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> validationHandler(org.springframework.validation.BindException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        String msg = "";
        for (FieldError error : fieldErrors) {
            msg += error.getDefaultMessage() + ";";
        }
        return buildResult(msg, HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> methodArgsValidationHandler(MethodArgumentNotValidException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        String msg = "";
        for (FieldError error : fieldErrors) {
            msg += error.getDefaultMessage() + ";";
        }
        return buildResult(msg, HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> illegalArgumentExceptionHandler(IllegalArgumentException ex) {
        return buildResult("请求参数中发现无效字符", HttpStatus.BAD_REQUEST.value(), ex);
    }

    @ResponseStatus(value = HttpStatus.OK)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<Void> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException ex) {
        return buildResult("请求方式" + ex.getMethod() + "不支持", HttpStatus.METHOD_NOT_ALLOWED.value(), ex);
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> runtimeExceptionHandler(RuntimeException ex) {
        return buildResult(ex.getMessage(), 550, ex);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> exceptionHandler(Exception ex) {
        return buildResult(ex.getMessage(), 500, ex);
    }

    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public R<Void> notLoginExceptionHandler(NotLoginException ex) {
        return buildResult(ex.getMessage(), 401, ex);
    }

    private R<Void> buildResult(String message, int code, Exception ex) {
        log.error("发生异常:{}", message, ex);
        return R.error(message, code);
    }
}
